using System;
using System.Collections.Generic;
using System.Text;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;

namespace Dan.Common.CusException
{
    /// <summary>
    /// 异常处理中间件基类
    /// </summary>
    public class BaseExceptionMiddleware
    {
        private readonly IHostingEnvironment env;
        private readonly ILogger logger;
        private readonly RequestDelegate next;

        public BaseExceptionMiddleware(RequestDelegate next,
            IHostingEnvironment env,
            ILogger<BaseExceptionMiddleware> logger)
        {
            this.next = next;
            this.env = env;
            this.logger = logger;
        }

        public virtual void AfterAddLog(RequestInfo ri, Exception ex)
        {
        }

        private void AddLog(RequestInfo ri, Exception ex)
        {
            var message = GetExceptionStr(ri, ex);
            logger.LogError(message);
            AfterAddLog(ri, ex);
        }


        public async Task Invoke(HttpContext context)
        {
            try
            {
                await next(context);
            }
            catch (Exception ex)
            {
                var innerEx = ex.GetBaseException();
                var request = context.Request;
                var ri = new RequestInfo
                {
                    Path = $"{RequestInfo.ServerUrl}{request.Path}",
                    Query = request.GetQueryStr(),
                    FormData = request.GetFormStr(),
                    Header = request.GetHeaderStr()
                };

                if (innerEx is MsgException)
                {
                    AddLog(ri, innerEx);
                    await HandleMsgExceptionAsync(context, ((MsgException) innerEx).Message);
                }
                else if (innerEx is ValidationException vex)
                {
                    AddLog(ri, innerEx);
                    await HandleValidationExceptionAsync(context, vex.Field, vex.Message);
                }
                else
                {
                    await HandlerExcepitionAsync(context, innerEx);

                    AddLog(ri, innerEx);
                }
            }
        }

        private string GetExceptionStr(RequestInfo ri, Exception ex)
        {
            var newLine = Environment.NewLine;

            var sb = new StringBuilder();
            sb.Append("//****************************************************\r\n");
            sb.Append($"异常时间：({DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss fff")})\r\n");
            sb.Append($"出错页面：({ri.Path})\r\n");
            sb.Append($"query参数信息：({ri.Query})\r\n");
            sb.Append($"form参数信息：({ri.FormData})\r\n");
            sb.Append($"header参数信息：({ri.Header})\r\n");
            var message = ex.Message;
            if (ex is MsgException) message = $"{((MsgException) ex).Message} {message}\r\n";

            if (ex is ValidationException) message = $"{((ValidationException) ex).Message} {message}\r\n";

            sb.Append($"异常信息：({message})\r\n");
            sb.Append($"异常方法：({ex.TargetSite})\r\n");
            sb.Append($"异常来源：({ex.Source})\r\n");
            sb.Append("异常处理：" + newLine + ex.StackTrace.Replace("   ", "\r\n   ").Replace("--- ", "\r\n--- ") +
                      "\r\n");
            sb.Append("异常实例：" + newLine + ex.InnerException + "\r\n");
            sb.Append("//*******************************************************\r\n");
            return sb.ToString();
        }

        /// <summary>
        ///     普通错误,记录日志
        /// </summary>
        /// <param name="context"></param>
        /// <param name="ex"></param>
        /// <returns></returns>
        private Task HandlerExcepitionAsync(HttpContext context, Exception ex)
        {
            var data = new Result
            {
                code = 500,
                msg = $"发生异常:{ex.Message}"
            };

            var result = JsonConvert.SerializeObject(data).ToLower();

            context.Response.ContentType = "application/json;charset=utf-8";
            return context.Response.WriteAsync(result);
        }

        /// <summary>
        ///     错误验证错误
        /// </summary>
        /// <param name="context"></param>
        /// <param name="field"></param>
        /// <param name="message"></param>
        /// <returns></returns>
        private Task HandleValidationExceptionAsync(HttpContext context, string field, string message)
        {
            var data = new Result
            {
                code = 400,
                msg = $"{field} : {message}",
                data = false,
                count = 0,
            };

            var result = JsonConvert.SerializeObject(data).ToLower();

            context.Response.ContentType = "application/json;charset=utf-8";
            return context.Response.WriteAsync(result);
        }

        /// <summary>
        ///     操作错误
        /// </summary>
        /// <param name="context"></param>
        /// <param name="msg"></param>
        /// <returns></returns>
        private Task HandleMsgExceptionAsync(HttpContext context, string msg)
        {
            var data = new Result
            {
                code = 500,
                msg = msg,
                data = false,
            };

            var result = JsonConvert.SerializeObject(data).ToLower();

            context.Response.ContentType = "application/json;charset=utf-8";
            return context.Response.WriteAsync(result);
        }
    }
}